package cn.iocoder.yudao.module.trade.service.depositorderreturn;

import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.infra.api.code.AutoCodeUtilsApi;
import cn.iocoder.yudao.module.member.api.user.CrmMemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.CrmMemberUserRespDTO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.trade.controller.admin.depositorderreturnlog.vo.DepositOrderReturnLogRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.depositorder.DepositOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.depositorderreturnlog.DepositOrderReturnLogDO;
import cn.iocoder.yudao.module.trade.dal.mysql.depositorder.DepositOrderMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.depositorderreturnlog.DepositOrderReturnLogMapper;
import cn.iocoder.yudao.module.trade.service.depositorderreturnlog.DepositOrderReturnLogService;
import cn.iocoder.yudao.module.trade.service.depositproductrelation.DepositProductRelationService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.trade.controller.admin.depositorderreturn.vo.*;
import cn.iocoder.yudao.module.trade.dal.dataobject.depositorderreturn.DepositOrderReturnDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.trade.dal.mysql.depositorderreturn.DepositOrderReturnMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;

/**
 * 押金单退瓶 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class DepositOrderReturnServiceImpl implements DepositOrderReturnService {

    @Resource
    private DepositOrderReturnMapper depositOrderReturnMapper;

    @Resource
    private AutoCodeUtilsApi autoCodeUtilsApi;

    @Resource
    private DepositProductRelationService depositProductRelationService;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private CrmMemberUserApi crmMemberUserApi;

    @Resource
    private DepositOrderReturnLogService depositOrderReturnLogService;

    @Resource
    private DepositOrderReturnLogMapper depositOrderReturnLogMapper;

    @Resource
    private DepositOrderMapper depositOrderMapper;
    @Resource
    private DeptApi deptApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createDepositOrderReturn(DepositOrderReturnSaveReqVO createReqVO) {
        // 校验是否有未完成确认的退单
        LambdaQueryWrapperX<DepositOrderReturnDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper.eq(DepositOrderReturnDO ::getDepositId, createReqVO.getDepositId() );
        List<DepositOrderReturnDO> returnDOList = depositOrderReturnMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(returnDOList)) {
            List<DepositOrderReturnDO> collect = returnDOList.stream().filter(x -> x.getStatus() == 0).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)){
                throw exception(DEPOSIT_ORDER_RETURN_NOT_CONFIRM);
            }
        }
        createReqVO.setCode(autoCodeUtilsApi.autoCode("deposit_return", autoCodeUtilsApi.timeCode()));
        // 插入
        DepositOrderReturnDO depositOrderReturn = BeanUtils.toBean(createReqVO, DepositOrderReturnDO.class);

        // 如果押金总瓶数 == 退瓶数量 则直接完成退瓶单 并修改状态为 ：全部退瓶已消单=5
        if (Objects.equals(createReqVO.getBottleReturnCount(), createReqVO.getScanBottleReturnCount())) {
            // 退瓶记录状态设置为 已完成
            depositOrderReturn.setStatus(1);

            // 更新押金单
            depositOrderMapper.updateById(new DepositOrderDO().setId(createReqVO.getDepositId()).setStatus(5));
        }

        depositOrderReturn.setStartTime(LocalDateTime.now());
        CrmMemberUserRespDTO crmMemberById = crmMemberUserApi.getCrmMemberById(createReqVO.getCrmGasUserId());
        depositOrderReturn.setCrmName(crmMemberById.getName());
        depositOrderReturn.setMobile(crmMemberById.getMobile());
        depositOrderReturn.setConfirmName(adminUserApi.getUser(SecurityFrameworkUtils.getLoginUser().getId()).getUsername());
        depositOrderReturnMapper.insert(depositOrderReturn);

        List<DepositOrderReturnLogRespVO> voList = createReqVO.getReturnLogList();
        voList.forEach(x -> {
            x.setReturnId(depositOrderReturn.getId());
        });
        depositOrderReturnLogService.createDepositOrderReturnLogList(voList);
        // 返回
        return depositOrderReturn.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDepositOrderReturn(DepositOrderReturnSaveReqVO updateReqVO) {
        // 校验存在
        validateDepositOrderReturnExists(updateReqVO.getId());

        // 更新
        DepositOrderReturnDO updateObj = BeanUtils.toBean(updateReqVO, DepositOrderReturnDO.class);


//        // 确认退瓶操作
        if (updateReqVO.getStatus() == 1) {
            // 设置确认人Id
            updateObj.setConfirmId(WebFrameworkUtils.getLoginUserId());
            //确认时间
            updateObj.setConfirmTime(LocalDateTime.now());

            updateObj.setEndTime(LocalDateTime.now());

            DepositOrderDO depositOrderDO = depositOrderMapper.selectById(updateReqVO.getDepositId());
            // 如果已被处理 则提示已完成
            if (depositOrderDO.getResidueCount() == 0) {
                throw exception(DEPOSIT_ORDER_RETURN_CONFIRM);
            }

            if (CollectionUtils.isNotEmpty(updateReqVO.getReturnLogList())) {
                int i = depositOrderDO.getResidueCount();
                updateReqVO.getReturnLogList().forEach(x -> {
                    x.setResidueCount(i - x.getBottleReturnCount());
                });
                depositOrderReturnLogMapper.updateBatch(BeanUtils.toBean(updateReqVO.getReturnLogList(), DepositOrderReturnLogDO.class));
            }


            // 确认退瓶后 更改押金单状态
            DepositOrderDO order = new DepositOrderDO();
            order.setId(updateReqVO.getDepositId());
            //更新剩余数量
            Integer count = depositOrderDO.getResidueCount() - updateObj.getBottleReturnCount();
            order.setResidueCount(count);
            if (count > 0) {
                //部分退瓶
                order.setStatus(4);
            } else {
                //                押金单状态为全部退瓶已消单
                order.setStatus(5);
            }
            depositOrderMapper.updateById(order);


            LambdaQueryWrapperX<DepositOrderReturnLogDO> wrapper = new LambdaQueryWrapperX<>();
            wrapper.eqIfPresent(DepositOrderReturnLogDO ::getReturnId, updateReqVO.getId());

            // 更新钢瓶信息表  钢瓶数量
            depositProductRelationService.updateDepositProductRelationBySkuId(depositOrderReturnLogMapper.selectList(wrapper), updateReqVO.getDepositId());
        }
        // 更新退瓶记录
        depositOrderReturnMapper.updateById(updateObj);
    }

    @Override
    public void deleteDepositOrderReturn(Long id) {
        // 校验存在
        validateDepositOrderReturnExists(id);
        // 删除
        depositOrderReturnMapper.deleteById(id);
    }

    private void validateDepositOrderReturnExists(Long id) {
        if (depositOrderReturnMapper.selectById(id) == null) {
            throw exception(DEPOSIT_ORDER_RETURN_NOT_EXISTS);
        }
    }

    @Override
    public DepositOrderReturnRespVO getDepositOrderReturn(Long id) {
        DepositOrderReturnRespVO returnRespVO = BeanUtils.toBean(depositOrderReturnMapper.selectById(id), DepositOrderReturnRespVO.class);
        // 查询对应确认人
        if (null != returnRespVO.getConfirmId()) {
            returnRespVO.setConfirmName(adminUserApi.getUser(returnRespVO.getConfirmId()).getNickname());
        }
        LambdaQueryWrapperX<DepositOrderReturnDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper.eq(DepositOrderReturnDO ::getDepositId, returnRespVO.getDepositId() )
                .eq(DepositOrderReturnDO ::getStatus, 1 );
        Integer sum = depositOrderReturnMapper.selectList(wrapper).stream().collect(Collectors.summingInt(DepositOrderReturnDO::getBottleReturnCount));
        // 设置已退数量
        returnRespVO.setBottleReturned(sum);
        // 查询对应燃气户信息
        CrmMemberUserRespDTO crmMemberById = crmMemberUserApi.getCrmMemberById(returnRespVO.getCrmGasUserId());
        returnRespVO.setCrmAddress(crmMemberById.getDetailAddress());
        returnRespVO.setCrmCode(crmMemberById.getCode());
        returnRespVO.setCrmMobile(crmMemberById.getMobile());
        returnRespVO.setCrmName(crmMemberById.getName());
        returnRespVO.setDesipotRemark(depositOrderMapper.selectById(returnRespVO.getDepositId()).getRemark());

        LambdaQueryWrapperX<DepositOrderReturnLogDO> wrapper1 = new LambdaQueryWrapperX<>();
        wrapper1.eq(DepositOrderReturnLogDO::getReturnId, id);
        returnRespVO.setReturnLogList(BeanUtils.toBean(depositOrderReturnLogMapper.selectList(wrapper1), DepositOrderReturnLogRespVO.class));
        return returnRespVO;
    }

    @Override
    public PageResult<DepositOrderReturnRespVO> getDepositOrderReturnPage(DepositOrderReturnPageReqVO pageReqVO) {
        PageResult<DepositOrderReturnRespVO> result = BeanUtils.toBean(depositOrderReturnMapper.selectPage(pageReqVO), DepositOrderReturnRespVO.class);
        if (CollectionUtils.isNotEmpty(result.getList())) {
            result.getList().forEach(x -> {
                // 查询对应确认人
                if (null != x.getConfirmId()) {
                    x.setConfirmName(adminUserApi.getUser(x.getConfirmId()).getNickname());
                }
                // 查询对应燃气户信息
                CrmMemberUserRespDTO crmMemberById = crmMemberUserApi.getCrmMemberById(x.getCrmGasUserId());
                x.setCrmAddress(crmMemberById.getDetailAddress());
                x.setCrmCode(crmMemberById.getCode());
                x.setCrmMobile(crmMemberById.getMobile());
                x.setCrmName(crmMemberById.getName());
                x.setDeptName(deptApi.getDept(x.getDeptId()).getName());
                x.setDepositCode(depositOrderMapper.selectById(x.getDepositId()).getCode());

            });
            return result;
        }
        return new PageResult<>();
    }

    @Override
    public List<DepositOrderReturnDO> getDepositOrderReturnList(DepositOrderReturnPageReqVO pageReqVO) {
        return depositOrderReturnMapper.selectPage(pageReqVO).getList();
    }

    @Override
    public List<DepositOrderReturnRespVO> getDepositOrderReturnByDepositId(Long id, Integer status) {
        LambdaQueryWrapperX<DepositOrderReturnDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eq(DepositOrderReturnDO ::getDepositId, id );
        queryWrapper.eqIfPresent(DepositOrderReturnDO ::getStatus, status );

        List<DepositOrderReturnDO> depositOrderReturnDOS = depositOrderReturnMapper.selectList(queryWrapper);
        return BeanUtils.toBean(depositOrderReturnDOS, DepositOrderReturnRespVO.class);
    }

}